﻿/*
 * This file is part of MonoStrategy.
 *
 * Copyright (C) 2010-2011 Christoph Husse
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authors: 
 *      # Christoph Husse
 * 
 * Also checkout our homepage: http://monostrategy.codeplex.com/
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Globalization;
using System.Drawing;
using System.IO;
using System.ComponentModel;
using System.Drawing.Imaging;
using MonoStrategy;

namespace MonoStrategy
{
    /// <summary>
    /// Interaction logic for AnimLibraryTab.xaml
    /// </summary>
    public partial class AnimLibraryTab : UserControl
    {
        private unsafe void BTN_MinimizeBounds_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;

            MemoryStream targetBytes = new MemoryStream();

            int globalLeft = TCurrentAnim.Width, globalTop = TCurrentAnim.Height;

            foreach (AnimationFrame frame in TCurrentAnim.Frames)
            {
                globalLeft = Math.Min(globalLeft, frame.OffsetX);
                globalTop = Math.Min(globalTop, frame.OffsetY);
            }

            foreach (AnimationFrame frame in TCurrentAnim.Frames)
            {
                Bitmap source = (Bitmap)Bitmap.FromStream(new MemoryStream(frame.ToArray()));
                ImagePixelLock locked = new ImagePixelLock(source, false);
                Int32 left = frame.Width, top = frame.Height, bottom = 0, right = 0;

                targetBytes.SetLength(0);

                using (locked)
                {
                    // compute smallest bounds of extracted animation frame
                    int* destPtr = locked.Pixels;

                    for (int y = 0; y < frame.Height; y++)
                    {
                        for (int x = 0; x < frame.Width; x++)
                        {
                            int pixel = *(destPtr++);

                            if (pixel == 0)
                                continue;

                            if (x < left)
                                left = x;

                            if (y < top)
                                top = y;

                            if (y > bottom)
                                bottom = y;

                            if (x > right)
                                right = x;
                        }
                    }
                }

                int newWidth = right - left, newHeight = bottom - top;

                if ((newWidth != frame.Width) || (newHeight != frame.Height))
                {
                    if ((newWidth > 0) && (newHeight > 0))
                    {
                        frame.OffsetX += left - globalLeft;
                        frame.OffsetY += top - globalTop;
                        frame.Height = newHeight;
                        frame.Width = newWidth;

                        // create new bitmap
                        Bitmap target = new Bitmap(frame.Width, frame.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                        Graphics gTarget = Graphics.FromImage(target);

                        using (gTarget)
                        {
                            gTarget.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;

                            gTarget.DrawImage(
                                source,
                                new System.Drawing.Rectangle(0, 0, frame.Width, frame.Height),
                                new System.Drawing.Rectangle(left, top, frame.Width, frame.Height),
                                GraphicsUnit.Pixel);
                        }

                        target.Save(targetBytes, ImageFormat.Png);

                        frame.SetBitmap(targetBytes.ToArray());
                    }
                    else
                    {
                        // normalize empty frames
                        frame.SetBitmap(EmptyBitmapBytes);
                        frame.Width = 1;
                        frame.Height = 1;
                    }
                }
            }

            GROUP_AnimDetails.DataContext = new Object();
            GROUP_AnimDetails.DataContext = TCurrentAnim;
        }

        private void BTN_RemoveDups_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;

            UniqueMap<Int64, Object> dups = new UniqueMap<long, object>();
            List<AnimationFrame> removals = new List<AnimationFrame>();

            foreach (AnimationFrame frame in TCurrentAnim.Frames)
            {
                if (dups.ContainsKey(frame.Checksum))
                    removals.Add(frame);
                else
                    dups.Add(frame.Checksum, null);
            }

            foreach (var frame in removals)
            {
                TCurrentAnim.RemoveFrame(frame);
            }

            GROUP_AnimDetails.DataContext = new Object();
            GROUP_AnimDetails.DataContext = TCurrentAnim;
        }

        private void BTN_StoreAtlas_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;

            Int32 maxFrameWidth = 0, fullHeight = 0, fullWidth = 0;

            foreach (AnimationFrame frame in TCurrentAnim.Frames)
            {
                fullHeight = Math.Max(fullHeight, frame.Height);
                maxFrameWidth = Math.Max(maxFrameWidth, frame.Width);
            }

            fullHeight = (fullHeight + 10) * TCurrentAnim.Frames.Count;
            fullWidth = (maxFrameWidth + 10) * TCurrentAnim.Frames.Count;

            Bitmap target;

            // align horizontal
            target = new Bitmap(fullWidth, fullHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
            Graphics gTarget = Graphics.FromImage(target);

            using (gTarget)
            {
                int offset = 0;

                foreach (AnimationFrame frame in TCurrentAnim.Frames)
                {
                    gTarget.DrawImageUnscaled(Bitmap.FromStream(new MemoryStream(frame.ToArray())), offset, 0);

                    offset += maxFrameWidth + 10;
                }
            }

            System.IO.File.Delete(".\\FrameAtlas.png");
            target.Save(".\\FrameAtlas.png", ImageFormat.Png);
        }

        private void BTN_LoadAtlas_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;

            Int32 maxFrameWidth = 0, fullHeight = 0, fullWidth = 0;

            foreach (AnimationFrame frame in TCurrentAnim.Frames)
            {
                fullHeight = Math.Max(fullHeight, frame.Height);
                maxFrameWidth = Math.Max(maxFrameWidth, frame.Width);
            }

            fullHeight = (fullHeight + 10) * TCurrentAnim.Frames.Count;
            fullWidth = (maxFrameWidth + 10) * TCurrentAnim.Frames.Count;

            if (!File.Exists(".\\FrameAtlas.png"))
            {
                MessageBox.Show("You have to store an atlas before loading it.");

                return;
            }

            Bitmap source = (Bitmap)Bitmap.FromFile(".\\FrameAtlas.png");

            using (source)
            {
                if ((fullWidth != source.Width) || (fullHeight != source.Height))
                {
                    MessageBox.Show("Stored atlas does not match current frame alignment!");

                    return;
                }

                //if ((fullWidth_Hor * fullHeight_Hor) < (fullHeight_Vert * fullWidth_Vert))
                {
                    // horizontal alignment
                    int offset = 0;
                    MemoryStream targetBytes = new MemoryStream();

                    foreach (AnimationFrame frame in TCurrentAnim.Frames)
                    {
                        Bitmap target = new Bitmap(frame.Width, frame.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                        Graphics gTarget = Graphics.FromImage(target);

                        targetBytes.SetLength(0);

                        using (target)
                        {
                            using (gTarget)
                            {
                                gTarget.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.None;

                                gTarget.DrawImage(
                                    source,
                                    new System.Drawing.Rectangle(0, 0, frame.Width, frame.Height),
                                    new System.Drawing.Rectangle(offset, 0, frame.Width, frame.Height),
                                    GraphicsUnit.Pixel);
                            }

                            target.Save(targetBytes, ImageFormat.Png);

                            frame.SetBitmap(targetBytes.ToArray());
                        }

                        offset += maxFrameWidth + 10;
                    }
                }
                //else
                {
                    // align vertical
                }
            }

            GROUP_AnimDetails.DataContext = new Object();
            GROUP_AnimDetails.DataContext = TCurrentAnim;
        }

         private void BTN_Clear_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;

            foreach (var frame in TCurrentAnim.Frames.ToArray())
            {
                TCurrentAnim.RemoveFrame(frame);
            }
        }

        private void BTN_MoveLeft_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;

            AnimationFrame item = LIST_AnimFrames.SelectedItem as AnimationFrame;

            if (item != null)
                TCurrentAnim.MoveFrameLeft(item);

            LIST_AnimFrames.SelectedItem = item;
        }

        private void BTN_MoveRight_Click(object sender, RoutedEventArgs e)
        {
            e.Handled = true;

            AnimationFrame item = LIST_AnimFrames.SelectedItem as AnimationFrame;

            if (item != null)
                TCurrentAnim.MoveFrameRight(item);

            LIST_AnimFrames.SelectedItem = item;
        }
    }
}
